﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Ext.h".
//-------------------------------------------------------------------

#include "opencl.h"

#ifdef _UXS_USE_OPENCL

#include "../OS/OS.h"


namespace UX_STL
{
namespace UXTypesExt
{
	
/*
=================================================
	проверить код ошибки
=================================================
*/
	bool TAPIErrorChecker::CheckCLError(cl_int iError, uni_c_string pCLFunc, uni_c_string pFunc, uni_c_string pFile, uint uLine)
	{
		if ( iError == CL_SUCCESS )
			return true;

		static const uint	s_uNumErrors = 64;

		static const char *	s_pErrors[s_uNumErrors] =
		{
			"CL_SUCCESS",
			"CL_DEVICE_NOT_FOUND",
			"CL_DEVICE_NOT_AVAILABLE",
			"CL_COMPILER_NOT_AVAILABLE",
			"CL_MEM_OBJECT_ALLOCATION_FAILURE",
			"CL_OUT_OF_RESOURCES",
			"CL_OUT_OF_HOST_MEMORY",
			"CL_PROFILING_INFO_NOT_AVAILABLE",
			"CL_MEM_COPY_OVERLAP",
			"CL_IMAGE_FORMAT_MISMATCH",
			"CL_IMAGE_FORMAT_NOT_SUPPORTED",
			"CL_BUILD_PROGRAM_FAILURE",
			"CL_MAP_FAILURE",
			"13",
			"14",
			"15",
			"16",
			"17",
			"18",
			"19",
			"20",
			"21",
			"22",
			"23",
			"24",
			"25",
			"26",
			"27",
			"28",
			"29",
			"CL_INVALID_VALUE",
			"CL_INVALID_DEVICE_TYPE",
			"CL_INVALID_PLATFORM",
			"CL_INVALID_DEVICE",
			"CL_INVALID_CONTEXT",
			"CL_INVALID_QUEUE_PROPERTIES",
			"CL_INVALID_COMMAND_QUEUE",
			"CL_INVALID_HOST_PTR",
			"CL_INVALID_MEM_OBJECT",
			"CL_INVALID_IMAGE_FORMAT_DESCRIPTOR",
			"CL_INVALID_IMAGE_SIZE",
			"CL_INVALID_SAMPLER",
			"CL_INVALID_BINARY",
			"CL_INVALID_BUILD_OPTIONS",
			"CL_INVALID_PROGRAM",
			"CL_INVALID_PROGRAM_EXECUTABLE",
			"CL_INVALID_KERNEL_NAME",
			"CL_INVALID_KERNEL_DEFINITION",
			"CL_INVALID_KERNEL",
			"CL_INVALID_ARG_INDEX",
			"CL_INVALID_ARG_VALUE",
			"CL_INVALID_ARG_SIZE",
			"CL_INVALID_KERNEL_ARGS",
			"CL_INVALID_WORK_DIMENSION",
			"CL_INVALID_WORK_GROUP_SIZE",
			"CL_INVALID_WORK_ITEM_SIZE",
			"CL_INVALID_GLOBAL_OFFSET",
			"CL_INVALID_EVENT_WAIT_LIST",
			"CL_INVALID_EVENT",
			"CL_INVALID_OPERATION",
			"CL_INVALID_GL_OBJECT",
			"CL_INVALID_BUFFER_SIZE",
			"CL_INVALID_MIP_LEVEL",
			"CL_INVALID_GLOBAL_WORK_SIZE"
		};

		string	str( "OpenCL error: " );

		if ( iError <= 0 and -iError < s_uNumErrors )
			str << s_pErrors[ -iError ];
		else
			str << "code: " << string().FormatI( iError, 10 );

		str << ", in " << pCLFunc;
		str << ", function: " << pFunc;

		LOG_EXT( str.cstr(), e_log_msg::ERROR_2, pFile.cstr(), uLine );
		return false;
	}

}	// UXTypesExt
}	// UX_STL


#ifndef UX_CL_PROTOTYPES

extern "C"
{
	

static	UX_STL::UXTypesExt::array< UX_STL::UXTypesExt::string >	_s_aCLLog;	
static	UX_STL::UXTypesExt::Library							_s_sCLLib(CL_LIBRARY_NAME);
static	UX_STL::UXTypesExt::atomic_int32						_s_iCLRefCounter;


static const char * CL_GetErrorString()
{
	static bool	bNeedDeleteLastString = false;

	if ( !_s_aCLLog.Empty() )
	{
		if ( bNeedDeleteLastString )
			_s_aCLLog.PopBack();

		if ( _s_aCLLog.Empty() )
			return null;

		bNeedDeleteLastString = true;

		return _s_aCLLog.Back().cstr();
	}
	else
		return null;
}

#define __ADD_TO_LOG( _text )			_s_aCLLog.PushFront( _text )

#define CL_GETPROCADDRESS( _address )	_s_sCLLib.GetProc( _address )


/* Init OpenCL Library */
#ifdef PLATFORM_WINDOWS
#	define OPENCL_INIT_LIB( _ret )		_ret = _s_sCLLib.Load( CL_LIBRARY_NAME )
#endif

#ifndef OPENCL_INIT_LIB
#	error not defined library initialization!
#endif


/* get OpenCL function address */
#if UX_CL_DEBUG_LOG == 0
#	define OPENCL_GET_PROC( p, n, d ) \
		if ( (n = (p)CL_GETPROCADDRESS( #n )) == null ) \
		{ \
			n = d; \
			ret &= false; \
		}
#else
#	define OPENCL_GET_PROC( p, n, d ) \
		if ( (n = (p)CL_GETPROCADDRESS( #n )) == null ) \
		{ \
			n = d; \
			__ADD_TO_LOG( "Can't get address of function \""#n"\"." ); \
			ret &= false; \
		}
#endif	// UX_CL_DEBUG_LOG


/* Create Default OpenCL functions */
#ifdef UX_CL_USE_DEFAULT_FUNC

	#undef  CL_BUILDFUNC
	#define CL_BUILDFUNC( _retType, _funcName, _funcParams, _retValue ) \
		CL_API _retType CL_API_CALL clDefault##_funcName _funcParams \
		{ \
			WARNING( #_funcName ); \
			return _retValue; \
		} \

	CL_FUNCTIONS_1_0
	CL_FUNCTIONS_1_1

	#undef  CL_BUILDFUNC
	#define CL_BUILDFUNC( _retType, _funcName, _funcParams, _retValue )

#endif	// UX_CL_USE_DEFAULT_FUNC



/* CL Functions */
#undef  CL_BUILDFUNC
#define CL_BUILDFUNC( _retType, _funcName, _funcParams, _retValue ) \
	cl##_funcName##_fn		cl##_funcName	= null;

CL_FUNCTIONS_1_0
CL_FUNCTIONS_1_1

#undef  CL_BUILDFUNC
#define CL_BUILDFUNC( _retType, _funcName, _funcParams, _retValue )



CL_API const char * CL_GetError()
{
	return CL_GetErrorString();
}

CL_API void CL_ClearErrors()
{
	_s_aCLLog.Clear();
}
	
CL_API bool CL_Delete()
{
	if ( --_s_iCLRefCounter == 0 )
		return _s_sCLLib.Unload();
	else
		return true;
}

CL_API char CL_Init()
{
	static bool		s_bInited = false;
	
	++_s_iCLRefCounter;

	if ( s_bInited )
		return 0;	// success

	bool	ret = true;

	OPENCL_INIT_LIB( ret );

	if ( !ret ) {
		__ADD_TO_LOG( "Error: can't find OpenCL library." );
		return 2;	// fail
	}

	#undef  CL_BUILDFUNC
	#ifdef UX_CL_USE_DEFAULT_FUNC
		#define CL_BUILDFUNC( _retType, _funcName, _funcParams, _retValue ) \
			OPENCL_GET_PROC( cl##_funcName##_fn,	cl##_funcName, &clDefault##_funcName );
	#else
		#define CL_BUILDFUNC( _retType, _funcName, _funcParams, _retValue ) \
			OPENCL_GET_PROC( cl##_funcName##_fn,	cl##_funcName, null );
	#endif	// UX_CL_USE_DEFAULT_FUNC

	CL_FUNCTIONS_1_0
	CL_FUNCTIONS_1_1

	#undef  CL_BUILDFUNC
	#define CL_BUILDFUNC( _retType, _funcName, _funcParams, _retValue )


	s_bInited = true;
	return ret ? 0 : 1;		// success or with errors
}


#undef	__ADD_TO_LOG
#undef	CL_GETPROCADDRESS
#undef	OPENCL_INIT_LIB
#undef	OPENCL_GET_PROC


}	// extern "C"

#endif	// UX_CL_PROTOTYPES
#endif	// _UXS_USE_OPENCL